﻿using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using GraphProcessor;
using IQIGame.Onigao.Logic;
using UnityEngine;
using Debug = UnityEngine.Debug;

namespace IQIGame.Onigao.GamePlay.Editors
{
    [System.Serializable, NodeMenuItem(SkillEditorConst.Battle + "/" + SkillEditorConst.Package + "参数/Int", typeof(SkillEditorGraph))]
    public class SkillEffectiveActionParamNode_Int : BaseNode
    {
        [Output] private SkillEffectiveAction_ParamNum output;
        public int value;

        protected override void Process()
        {
            this.output = new SkillEffectiveAction_ParamNum()
            {
                dataGuid = 0,
                key = -1,
                value = this.value,
            };
        }
    }

    [System.Serializable, NodeMenuItem(SkillEditorConst.Battle + "/" + SkillEditorConst.Package + "参数/Bool", typeof(SkillEditorGraph))]
    public class SkillEffectiveActionParamNode_Bool : BaseNode
    {
        [Output] private SkillEffectiveAction_ParamBool output;
        public bool value;

        protected override void Process()
        {
            this.output = new SkillEffectiveAction_ParamBool()
            {
                dataGuid = 0,
                key = -1,
                value = this.value
            };
        }
    }

    [System.Serializable, NodeMenuItem(SkillEditorConst.Battle + "/" + SkillEditorConst.Package + "参数/公式", typeof(SkillEditorGraph))]
    public class SkillEffectiveActionParamNode_Formula : BaseNode
    {
        protected int maxParamCount => 4;

        [Output] protected SkillEffectiveAction_ParamNum outputNum;
        [Output] protected SkillEffectiveAction_ParamBool outputBool;
        [Input("NumCount"), ShowAsDrawer, Tooltip("$0+")]
        public int numCount = 1;

        [Input("BoolCount"), ShowAsDrawer, Tooltip("$0+")]
        public int boolCount = 1;

        [Input(name = "Nums", allowMultiple = true)]
        public List<SkillEffectiveAction_ParamNum> nums = new List<SkillEffectiveAction_ParamNum>();

        [Input(name = "Bool", allowMultiple = true)]
        public List<SkillEffectiveAction_ParamBool> bools = new List<SkillEffectiveAction_ParamBool>();

        private List<PortData> numPorts = new List<PortData>();
        private List<PortData> boolPorts = new List<PortData>();

        [CustomPortBehavior(nameof(nums))]
        IEnumerable<PortData> GetPortsForInputs1(List<SerializableEdge> edges)
        {
            if (this.numCount > this.maxParamCount)
            {
                this.numCount = this.maxParamCount;
            }

            var nMaxCount = Mathf.Max(1, this.numCount);
            while (nMaxCount > this.numPorts.Count)
            {
                var nIndex = this.numPorts.Count;
                var rPort = new PortData() { displayName = $"Num {nIndex}", displayType = typeof(SkillEffectiveAction_ParamNum), identifier = $"Num {nIndex}" };
                this.numPorts.Add(rPort);
            }

            while (nMaxCount < this.numPorts.Count)
            {
                this.numPorts.RemoveAt(this.numPorts.Count - 1);
            }

            foreach (var portData in this.numPorts)
            {
                yield return portData;
            }
        }

        [CustomPortBehavior(nameof(bools))]
        IEnumerable<PortData> GetPortsForInputs2(List<SerializableEdge> edges)
        {
            if (this.boolCount > this.maxParamCount)
            {
                this.boolCount = this.maxParamCount;
            }

            var nMaxCount = Mathf.Max(1, this.boolCount);
            while (nMaxCount > this.boolPorts.Count)
            {
                var nIndex = this.boolPorts.Count;
                var rPort = new PortData() { displayName = $"Bool {nIndex}", displayType = typeof(SkillEffectiveAction_ParamBool), identifier = $"Bool {nIndex}" };
                this.boolPorts.Add(rPort);
            }

            while (nMaxCount < this.boolPorts.Count)
            {
                this.boolPorts.RemoveAt(this.boolPorts.Count - 1);
            }

            foreach (var portData in this.boolPorts)
            {
                yield return portData;
            }
        }

        public override void BeforePullData()
        {
            base.BeforePullData();
            this.nums.Clear();
            this.bools.Clear();
        }

        [CustomPortInput(nameof(nums), typeof(SkillEffectiveAction_ParamNum), allowCast = true)]
        public void GetInputsNum(List<SerializableEdge> edges)
        {
            this.nums.AddRange(edges.Where((e) => e.passThroughBuffer is SkillEffectiveAction_ParamNum).Select((e) => (SkillEffectiveAction_ParamNum)e.passThroughBuffer));
        }

        [CustomPortInput(nameof(bools), typeof(SkillEffectiveAction_ParamBool), allowCast = true)]
        public void GetInputsBool(List<SerializableEdge> edges)
        {
            this.bools.AddRange(edges.Where((e) => e.passThroughBuffer is SkillEffectiveAction_ParamBool).Select((e) => (SkillEffectiveAction_ParamBool)e.passThroughBuffer));
        }

        public int formulaID;

        protected override void Process()
        {
            var rFormula = new SkillEffectiveAction_ParamFormula()
            {
                formula = this.formulaID,
            };
            if (this.nums != null)
            {
                while (this.numCount < this.nums.Count)
                {
                    this.nums.RemoveAt(this.nums.Count - 1);
                }

                rFormula.nums.AddRange(this.nums);
            }

            if (this.bools != null)
            {
                while (this.boolCount < this.bools.Count)
                {
                    this.bools.RemoveAt(this.bools.Count - 1);
                }

                rFormula.bools.AddRange(this.bools);
            }

            this.outputNum = new SkillEffectiveAction_ParamNum()
            {
                dataGuid = 0,
                key = -1,
                dynmicParam = rFormula,
                paramType = (int)SkillEffectiveAction_ParamBase.EActionParamType.Formula,
            };
            this.outputBool = new SkillEffectiveAction_ParamBool()
            {
                dataGuid = 0,
                key = -1,
                dynmicParam = rFormula,
                paramType = (int)SkillEffectiveAction_ParamBase.EActionParamType.Formula,
            };
        }
    }

    [System.Serializable, NodeMenuItem(SkillEditorConst.Battle + "/" + SkillEditorConst.Package + "参数/伤害公式", typeof(SkillEditorGraph))]
    public class SkillEffectiveActionParamNode_DamageFormula : BaseNode
    {
        public override Color color => Color.magenta;
        protected int maxParamCount => 2;

        [Output] protected SkillEffectiveAction_ParamNum outputNum;

        [Input("NumCount"), ShowAsDrawer, Tooltip("$2+")]
        public int numCount = 1;

        [Input("BoolCount"), ShowAsDrawer, Tooltip("$2+")]
        public int boolCount = 1;

        [Input(name = "Nums", allowMultiple = true)]
        public List<SkillEffectiveAction_ParamNum> nums = new List<SkillEffectiveAction_ParamNum>();

        [Input(name = "Bool", allowMultiple = true)]
        public List<SkillEffectiveAction_ParamBool> bools = new List<SkillEffectiveAction_ParamBool>();

        private List<PortData> numPorts = new List<PortData>();
        private List<PortData> boolPorts = new List<PortData>();

        [CustomPortBehavior(nameof(nums))]
        IEnumerable<PortData> GetPortsForInputs1(List<SerializableEdge> edges)
        {
            if (this.numCount > this.maxParamCount)
            {
                this.numCount = this.maxParamCount;
            }

            var nMaxCount = Mathf.Max(1, this.numCount);
            while (nMaxCount > this.numPorts.Count)
            {
                var nIndex = this.numPorts.Count;
                var rPort = new PortData() { displayName = $"Num {nIndex}", displayType = typeof(SkillEffectiveAction_ParamNum), identifier = $"Num {nIndex}" };
                this.numPorts.Add(rPort);
            }

            while (nMaxCount < this.numPorts.Count)
            {
                this.numPorts.RemoveAt(this.numPorts.Count - 1);
            }

            foreach (var portData in this.numPorts)
            {
                yield return portData;
            }
        }

        [CustomPortBehavior(nameof(bools))]
        IEnumerable<PortData> GetPortsForInputs2(List<SerializableEdge> edges)
        {
            if (this.boolCount > this.maxParamCount)
            {
                this.boolCount = this.maxParamCount;
            }

            var nMaxCount = Mathf.Max(1, this.boolCount);
            while (nMaxCount > this.boolPorts.Count)
            {
                var nIndex = this.boolPorts.Count;
                var rPort = new PortData() { displayName = $"Bool {nIndex}", displayType = typeof(SkillEffectiveAction_ParamBool), identifier = $"Bool {nIndex}" };
                this.boolPorts.Add(rPort);
            }

            while (nMaxCount < this.boolPorts.Count)
            {
                this.boolPorts.RemoveAt(this.boolPorts.Count - 1);
            }

            foreach (var portData in this.boolPorts)
            {
                yield return portData;
            }
        }

        public override void BeforePullData()
        {
            base.BeforePullData();
            this.nums.Clear();
            this.bools.Clear();
        }

        [CustomPortInput(nameof(nums), typeof(SkillEffectiveAction_ParamNum), allowCast = true)]
        public void GetInputsNum(List<SerializableEdge> edges)
        {
            this.nums.AddRange(edges.Where((e) => e.passThroughBuffer is SkillEffectiveAction_ParamNum).Select((e) => (SkillEffectiveAction_ParamNum)e.passThroughBuffer));
        }

        [CustomPortInput(nameof(bools), typeof(SkillEffectiveAction_ParamBool), allowCast = true)]
        public void GetInputsBool(List<SerializableEdge> edges)
        {
            this.bools.AddRange(edges.Where((e) => e.passThroughBuffer is SkillEffectiveAction_ParamBool).Select((e) => (SkillEffectiveAction_ParamBool)e.passThroughBuffer));
        }

        public int formulaID;

        protected override void Process()
        {

            var rFormula = new SkillEffectiveAction_ParamDamageFormula()
            {
                formula = this.formulaID,
            };
            if (this.nums != null)
            {
                while (this.numCount < this.nums.Count)
                {
                    this.nums.RemoveAt(this.nums.Count - 1);
                }

                rFormula.nums.AddRange(this.nums);
            }

            if (this.bools != null)
            {
                while (this.boolCount < this.bools.Count)
                {
                    this.bools.RemoveAt(this.bools.Count - 1);
                }

                rFormula.bools.AddRange(this.bools);
            }

            this.outputNum = new SkillEffectiveAction_ParamNum()
            {
                dataGuid = 0,
                key = -1,
                dynmicParam = rFormula,
                paramType = (int)SkillEffectiveAction_ParamBase.EActionParamType.DamageFormula,
            };
        }
    }

    [System.Serializable, NodeMenuItem(SkillEditorConst.Battle + "/" + SkillEditorConst.Package + "参数/技能上下文", typeof(SkillEditorGraph))]
    public class SkillEffectiveActionParamNode_SkillCorrect : BaseNode
    {
        [Input("触发器参数"), Tooltip("不可跨part")] private SkillEffectiveAction_ParamCorrect input;
        [Output] private SkillEffectiveAction_ParamNum outputNum;

        public SkillEffectiveAction_ParamCorrect.EParamCorrectType type;

        protected override void Process()
        {
            var rCorrect = new SkillEffectiveAction_ParamCorrect()
            {
                type = (int)this.type
            };
            this.outputNum = new SkillEffectiveAction_ParamNum()
            {
                dataGuid = 0,
                key = -1,
                dynmicParam = rCorrect,
                paramType = (int)SkillEffectiveAction_ParamBase.EActionParamType.SkillCorrect,
            };
        }
    }
}